/*=========================================================================
This file is part of CustusX, an Image Guided Therapy Application.
                 
Copyright (c) SINTEF Department of Medical Technology.
All rights reserved.
                 
CustusX is released under a BSD 3-Clause license.
                 
See Lisence.txt (https://github.com/SINTEFMedtek/CustusX/blob/master/License.txt) for details.
=========================================================================*/


#ifndef CXGPUIMAGEBUFFER_H_
#define CXGPUIMAGEBUFFER_H_

#include "cxResourceExport.h"
#include "cxPrecompiledHeader.h"

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <map>
#include <list>
#include "vtkForwardDeclarations.h"

namespace cx
{

/**
 * \file
 * \addtogroup cx_resource_core_data
 * @{
 */

/** \brief Helper class for sharing GPU memory over several Views (GL contexts).
 *
 * This one stores 3D volume texture in the form of a vtkImageDataPtr
 *
 */
class cxResource_EXPORT GPUImageDataBuffer
{
public:
	virtual ~GPUImageDataBuffer() {}
	/** Allocate resources for the volume on the GPU.
	 *
	 *  Call this from inside a PrepareForRendering() method in vtk.
	 */
	virtual void allocate(int textureUnitIndex) = 0;
//	/** Assuming imageData is changed,
//	  * send vtkImageData to GPU.
//	  */
//	virtual void updateTexture() = 0;
	/**Activate and bind the volume and lut buffers inside the texture units
	 * GL_TEXTURE<2X> and GL_TEXTURE<2X+1>.
	 * Use during RenderInternal()
	 */
	virtual void bind(int textureUnitIndex) = 0;
	virtual int getMemorySize() = 0;

	/** Return the texture uid for this object,
	  * as generated by glGenTextures().
	  *
	  * Prerequisite: allocate() has been called.
	  */
	virtual unsigned int getTextureUid() const = 0;
	//virtual vtkImageDataPtr getVtkImageData() = 0;
};

typedef boost::shared_ptr<GPUImageDataBuffer> GPUImageDataBufferPtr;
typedef boost::weak_ptr<GPUImageDataBuffer> GPUImageDataBufferWeakPtr;

cxResource_EXPORT GPUImageDataBufferPtr createGPUImageDataBuffer(vtkImageDataPtr volume);

/**\brief Helper class for sharing GPU memory over several Views (GL contexts).
 *
 * This one stores lut in the form of a vtkUnsignedCharArrayPtr
 *
 */
class cxResource_EXPORT GPUImageLutBuffer
{
public:
	virtual ~GPUImageLutBuffer() {}
	/** Allocate resources for the lookup table and the volume on the GPU.
	 *  Prerequisite: SetImage and SetcolorTable has been called.
	 *
	 *  Call this from inside a PrepareForRendering() methods in vtk.
	 */
	virtual void allocate() = 0;
//	/** If data is changed, send data to GPU.
//	  */
//	virtual void updateTexture() = 0;
	/** Activate and bind the volume and lut buffers inside the texture units
	 *  GL_TEXTURE<2X> and GL_TEXTURE<2X+1>.
	 *  Use during RenderInternal()
	 */
	virtual void bind(int textureUnitIndex) = 0;
	/**Size of lut. Used by fragment shader.
	 */
	virtual int getLutSize() const = 0;
};

typedef boost::shared_ptr<GPUImageLutBuffer> GPUImageLutBufferPtr;
typedef boost::weak_ptr<GPUImageLutBuffer> GPUImageLutBufferWeakPtr;

cxResource_EXPORT GPUImageDataBufferPtr createGPUImageDataBuffer(vtkImageDataPtr volume);
cxResource_EXPORT GPUImageLutBufferPtr createGPUImageLutBuffer(vtkUnsignedCharArrayPtr lut);

/**\brief Repository for GPU buffers
 *
 * Use this repository for avoiding multiple allocations of buffer data. *
 *
 */
class cxResource_EXPORT GPUImageBufferRepository
{
public:
	static GPUImageBufferRepository* getInstance();
	static void shutdown();

	GPUImageDataBufferPtr getGPUImageDataBuffer(vtkImageDataPtr volume);
	GPUImageLutBufferPtr getGPUImageLutBuffer(vtkUnsignedCharArrayPtr lut);
	int getMemoryUsage(int *textures);
	/**
	 * Free all resources in the repository, for instance on session change
	 */
	void clear();
private:
	GPUImageBufferRepository();
	~GPUImageBufferRepository();
	class GPUImageBufferRepositoryInternal* mInternal;
	static GPUImageBufferRepository* mInstance;
	void tearDown();
};

// Not allowed to export static functions from dll on Windows,
// so we have to use this funciton instead of GPUImageBufferRepository::getInstance
cxResource_EXPORT GPUImageBufferRepository* getGPUImageBufferRepository();

/**
 * \}
 */

}

#endif /*CXGPUIMAGEBUFFER_H_*/
